package com.gr.aspect;

import com.auth0.jwt.interfaces.DecodedJWT;
import com.gr.annotation.LogAnnotation;
import com.gr.entity.Log;
import com.gr.service.ILogService;
import com.gr.util.JwtUtils;
import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.lang.reflect.Method;
import java.time.LocalDateTime;

@Component//让spring管理起来这个类
@Aspect//表示该类是一个增强类
public class LogAspect {
    /*@Autowired
    private RabbitTemplate rabbitTemplate;*/
    @Autowired
    private ILogService logService;
    private Logger logger= LoggerFactory.getLogger(LogAspect.class);
    //目标方法上面增加注解LogAnnotation的都是需要增加额外功能的目标方法
    @Pointcut("@annotation(com.gr.annotation.LogAnnotation)")
    public void pointcut(){}
    /**
     * 增加后置处理方法,后置增强日志记录方法
     * @param joinPoint 链接点，可以获取到目标对象的相关信息,日志记录浏览器调用方法信息
     */
    @After("pointcut()")//表示一个后置增强,绑定切入点
    public void logAfter(JoinPoint joinPoint){
        //signature可以获取到目标方法信息，比如方法名、参数
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();//获取到目标方法
        String name = method.getName();//拿到方法名
        Object[] args = joinPoint.getArgs();//目标方法参数列表,可能有多个参数
        //将数组转化为字符串方便查看
        String argsStr = StringUtils.join(args, "-");//参数
        LocalDateTime now = LocalDateTime.now();//时间
        //获取当前用户信息,用户信息在jwt里面，jwt又在request的header，所以我们需要获取request对象,java类不能直接拿request对象
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();//可以拿到request的Attributes
        String token = requestAttributes.getRequest().getHeader("authorization");
        String userid="";
        if (token!=null){
            //获取token里面的用户信息,要结束token工具
            DecodedJWT verify = JwtUtils.verify(token);
            //toDo 这里的userid？？
            userid = verify.getClaim("userid").asString();
        }
        //记录日志，记录谁在什么时间做了那个方法，传递的参数是什么
        //项目跑起来就没有控制台，这时候用日志工具来记录日志，指定日志级别
        logger.info("当前系统时间：{},当前用户是:{},进入到的方法是:{},携带的参数是:{}",now,userid,name,argsStr);
        String ip=requestAttributes.getRequest().getRemoteHost();
        //每个方法具体操作内容，需要每个方法上定义，获取到目标方法中的注解，获取注解中的属性，method就是目标方法
        Log log=new Log();
        LogAnnotation declaredAnnotation = method.getDeclaredAnnotation(LogAnnotation.class);
        String type = declaredAnnotation.type();//select
        String content = declaredAnnotation.content();//用户登录的操作
        //每个方法有具体的操作内容，需要每个方法上面定义
        log.setLogContent(content);
        log.setLogDate(now);
        log.setLogIp(ip);
        //操作类型，要获取到是增删改查，哪种操作
        log.setLogType(type);
        log.setUsername(userid);
        logService.save(log);//将数据插入数据库表中
        /*发消息
        rabbitTemplate.convertAndSend("X","XA",log);*/
    }
}
